package br.iars.service.impl;

import java.util.LinkedList;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.jws.WebService;

import br.iars.manager.ContextManager;
import br.iars.model.entity.Item;
import br.iars.model.entity.Preference;
import br.iars.model.entity.User;
import br.iars.service.RecommendationService;
import br.iars.service.exception.RecommendationServiceException;
import br.iars.service.type.AddContextRequest;
import br.iars.service.type.Context;
import br.iars.service.type.ElementList;
import br.iars.service.type.EstimatePreferenceRequest;
import br.iars.service.type.EstimatePreferenceResponse;
import br.iars.service.type.PreferenceItem;
import br.iars.service.type.RecommendRequest;
import br.iars.service.type.RecommendResponse;
import br.iars.service.type.RecommendedItem;
import br.iars.service.type.SetPreferenceRequest;
import br.iars.service.type.SetPreferencesRequest;

@Stateless
@WebService(serviceName = "RecommendationService", portName = "RecommendationServicePort", wsdlLocation = "/META-INF/wsdl/v01/RecommendationService.wsdl", targetNamespace = "http://service.iars.br/v01/RecommendationService", endpointInterface = "br.iars.service.RecommendationService")
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class RecommendationServiceImpl implements RecommendationService {

	@EJB
	private ContextManager manager;

	public void addContext(AddContextRequest params) throws RecommendationServiceException {
		String companyName = params.getCompany();
		String systemName = params.getSystem();
		Float minRate = params.getMinRate();
		Float maxRate = params.getMaxRate();
		String rateType = params.getRateType().value();

		manager.addContext(companyName, systemName, minRate, maxRate, rateType);
	}

	public void setPreference(SetPreferenceRequest params) throws RecommendationServiceException {
		PreferenceItem p = params.getPreference();
		Context c = params.getContext();

		try {
			manager.setPreference(c.getCompany(), c.getSystem(), p.getUserEmail(), p.getItemId(), p.getRate());
		} catch (Exception e) {
			throw new RecommendationServiceException("", e);
		}
	}

	public void setPreferences(SetPreferencesRequest params) throws RecommendationServiceException {
		Context context = params.getContext();
		ElementList<PreferenceItem> preferencesItens = params.getPreferences();

		Preference p = null;
		List<Preference> preferences = new LinkedList<Preference>();

		for (PreferenceItem preferenceItem : preferencesItens.getItens()) {
			p = new Preference();
			p.setUser(new User(preferenceItem.getUserEmail()));
			p.setItem(new Item(preferenceItem.getItemId(), null));
			p.setRate(preferenceItem.getRate());

			preferences.add(p);
		}

		manager.setPreferences(context.getCompany(), context.getSystem(), preferences);
	}

	public RecommendResponse recommend(RecommendRequest params) throws RecommendationServiceException {

		try {

			String companyName = params.getContext().getCompany();
			String systemName = params.getContext().getSystem();
			String userEmail = params.getUserEmail();
			int quantity = params.getQuantity();
			boolean isOnlyOwnContext = params.isOnlyOwnContext();

			List<Preference> preferences = manager.recommend(companyName, systemName, userEmail, quantity, isOnlyOwnContext);

			ElementList<RecommendedItem> recommendations = null;
			if (preferences != null) {
				recommendations = new ElementList<RecommendedItem>();

				for (Preference p : preferences) {
					RecommendedItem recommendedItem = new RecommendedItem();
					recommendedItem.setItemId(p.getItem().getCode());
					recommendedItem.setRate(p.getRate());
					recommendations.getItens().add(recommendedItem);
				}
			}

			List<User> users = manager.getNeighbors(companyName, systemName, userEmail, isOnlyOwnContext);

			ElementList<String> neighbors = new ElementList<String>();
			if (users != null) {
				for (User user : users) {
					neighbors.getItens().add(user.getEmail());
				}
			}

			RecommendResponse response = new RecommendResponse();
			response.setItens(recommendations);
			response.setNeighbors(neighbors);
			return response;
		} catch (Exception e) {
			throw new RecommendationServiceException("", e);
		}

	}

	public EstimatePreferenceResponse estimatePreference(EstimatePreferenceRequest params) throws RecommendationServiceException {

		try {
			String companyName = params.getContext().getCompany();
			String systemName = params.getContext().getSystem();
			String userEmail = params.getUserEmail();
			long itemId = params.getItemId();
			boolean isOnlyOwnContext = params.isOnlyOwnContext();

			Float rate = manager.estimatePreference(companyName, systemName, userEmail, itemId, isOnlyOwnContext);
			List<User> users = manager.getNeighbors(companyName, systemName, userEmail, isOnlyOwnContext);

			ElementList<String> neighbors = new ElementList<String>();
			if (users != null) {
				for (User user : users) {
					neighbors.getItens().add(user.getEmail());
				}
			}

			EstimatePreferenceResponse response = new EstimatePreferenceResponse();
			response.setRate(rate);
			response.setNeighbors(neighbors);
			return response;
		} catch (Exception e) {
			throw new RecommendationServiceException("", e);
		}

	}

}
